package com.kancy.netclass;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author huangchengkang
 * @date 2018-10-11 17:18
 */
public class InvokeHelper {
    private static InvokeHelper invokeHelper;
    private static ClassLoader classLoader;

    static{
        //加载网络jar
        NetClassLoader.newInstance().addURL("http://central.maven.org/maven2/com/alibaba/fastjson/1.2.51/fastjson-1.2.51.jar");
    }

    private InvokeHelper() {
    }

    /**
     * 创建示例
     */
    public static InvokeHelper newInstance() {
        return newInstance(ClassLoader.getSystemClassLoader());
    }

    /**
     * double check 创建示例
     */
    public static InvokeHelper newInstance(ClassLoader zClassLoader) {
        if(invokeHelper == null){
            synchronized (InvokeHelper.class){
                if(invokeHelper == null){
                    invokeHelper = new InvokeHelper();
                    if(zClassLoader != null){
                        classLoader = zClassLoader;
                    }
                }
            }
        }
        return invokeHelper;
    }

    /**
     * 加载Class
     * @param className
     * @return
     * @throws ClassNotFoundException
     */
    public Class<?> loadClass(String className) throws ClassNotFoundException {
        return getClassLoader().loadClass(className);
    }

    /**
     * 加载方法
     * @param className
     * @param methodName
     * @param parameterTypes
     * @return
     * @throws ClassNotFoundException
     * @throws NoSuchMethodException
     */
    public Method loadMethod(String className, String methodName, Class<?> ... parameterTypes)
            throws ClassNotFoundException, NoSuchMethodException {
        return loadClass(className).getMethod(methodName, parameterTypes);
    }

    /**
     * 方法调用1
     * @param className
     * @param methodName
     * @return
     */
    public Object invoke(String className, String methodName)
            throws NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException {
        return invoke(className,methodName, null, null, false);
    }

    /**
     * 静态方法调用
     * @param className
     * @param methodName
     * @return
     */
    public Object staticInvoke(String className, String methodName)
            throws NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException {
        return invoke(className,methodName, null, null, true);
    }

    public Object invoke(String className, String methodName, Class<?>[] parameterTypes, Object[] args)
            throws NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
        return invoke(className,methodName, null, null, false);
    }

    /**
     * 方法调用2
     * @param className
     * @param methodName
     * @param parameterTypes
     * @param args
     * @return
     */
    public Object invoke(String className, String methodName, Class<?>[] parameterTypes, Object[] args, boolean staticCallable)
            throws NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
        Object invokeValue = null;
        Class<?> aClass = loadClass(className);
        Method method = aClass.getMethod(methodName, parameterTypes);
        boolean methodAccessible = method.isAccessible();
        try {
            method.setAccessible(true);
            invokeValue = method.invoke(staticCallable ? aClass : aClass.newInstance() ,args );
        } finally {
            method.setAccessible(methodAccessible);
        }
        return invokeValue;
    }

    private ClassLoader getClassLoader() {
        return classLoader;
    }
}
